package com.handpay.nocardpay.baselibrary.qualificationinfo.comm;

import android.os.Environment;
import android.util.Log;
import android.util.SparseArray;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created on 2017/11/2.<br/>
 * 高效sd卡图片文件扫描器
 * @author fplei
 */
public class OkImageScanner {
    public final static String TAG=OkImageScanner.class.getSimpleName();
    private static OkImageScanner okImageScanner = null;
    /**
     * 工作扫描线程数量
     */
    private int scannerThreadSize = 1;
    /**
     * 遍历出来的图片
     */
    private LinkedList<String> images = null;
    /**
     * 线程池
     */
    private ExecutorService threadPool = null;
    /**
     * 开始时间
     */
    private long startTime=0L;
    /**
     * 线程池容量
     */
    private int corePoolSize=10;

    private ImageScannerResultListener imageScannerResultListener=null;

    /**
     * 扫描监听
     */
    public interface ImageScannerResultListener{
        /**
         * 激活该回调
         * @param startScannerTime
         * @param imageName 图片名称
         * @param imagePath 图片地址
         */
        void scannerSingeResult(long startScannerTime, String imageName, String imagePath);
    }

    /**
     * SD卡相关操作
     */
    public static class SdCardHelper {
        public static boolean sdCardIsWork() {
            return android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
        }

        /**
         * 遍历 "system/etc/vold.fstab” 文件，获取全部的Android的挂载点信息
         */
        private static ArrayList<String> getDevMountList() {
            String[] toSearch = SdCardHelper.readFile("/system/etc/vold.fstab").split(" ");
            ArrayList<String> out = new ArrayList<String>();
            for (int i = 0; i < toSearch.length; i++) {
                if (toSearch[i].contains("dev_mount")) {
                    if (new File(toSearch[i + 2]).exists()) {
                        out.add(toSearch[i + 2]);
                    }
                }
            }
            return out;
        }

        /**
         * 获取扩展SD卡存储目录
         * <p>
         * 如果有外接的SD卡，并且已挂载，则返回这个外置SD卡目录
         * 否则：返回内置SD卡目录
         *
         * @return
         */
        public static String getExternalSdCardPath() {
            if (sdCardIsWork()) {
                File sdCardFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath());
                return sdCardFile.getAbsolutePath();
            }
            String path = null;
            File sdCardFile = null;
            ArrayList<String> devMountList = getDevMountList();
            for (String devMount : devMountList) {
                File file = new File(devMount);
                if (file.isDirectory() && file.canWrite()) {
                    path = file.getAbsolutePath();
                    String timeStamp = new SimpleDateFormat("ddMMyyyy_HHmmss").format(new Date());
                    File testWritable = new File(path, "test_" + timeStamp);
                    if (testWritable.mkdirs()) {
                        testWritable.delete();
                    } else {
                        path = null;
                    }
                }
            }
            if (path != null) {
                sdCardFile = new File(path);
                return sdCardFile.getAbsolutePath();
            }
            return path;
        }
        public static String readFile(String filePath) {
            String fileContent = "";
            File file = new File(filePath);
            if (file == null || !file.isFile()) {
                return null;
            }
            BufferedReader reader = null;
            try {
                InputStreamReader is = new InputStreamReader(new FileInputStream(file));
                reader = new BufferedReader(is);
                String line = null;
                int i = 0;
                while ((line = reader.readLine()) != null) {
                    fileContent += line + " ";
                }
                reader.close();
                return fileContent;
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return fileContent;
        }
    }
    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        @Override
        public Thread newThread(Runnable r) {
            return new Thread(r, "OkImageScannerAsyncTask #" + mCount.getAndIncrement());
        }
    };

    private OkImageScanner() {
        images = new LinkedList<>();
        threadPool = new ThreadPoolExecutor(corePoolSize, 20, 0L,
                TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1024), sThreadFactory, new ThreadPoolExecutor.AbortPolicy());
    }

    public static OkImageScanner with() {
        if (okImageScanner == null) {
            synchronized (OkImageScanner.class) {
                if (okImageScanner == null) {
                    okImageScanner = new OkImageScanner();
                }
            }
        }
        return okImageScanner;
    }

    /**
     *开始扫描
     */
    public void startScanner() {
        String sdCardPath= SdCardHelper.getExternalSdCardPath();
        Log.i(TAG,"sdCardPath:"+sdCardPath);
        if (SdCardHelper.sdCardIsWork()) {
            startTime= System.currentTimeMillis();
            Log.i(TAG,"开始扫描..."+startTime);
            if (threadPool != null && images != null) {
                Log.i(TAG,"sdPath:"+sdCardPath);
                SparseArray<List<File>> batchFiles = calculateScannerThreadBatch(sdCardPath);
                for (int i = 0, nSize = batchFiles.size(); i < nSize; i++) {
                    int key=batchFiles.keyAt(i);
                    List<File> files = batchFiles.valueAt(i);
                    doBatchTask(key,files);
                }
            }
        }else{
            Log.e(TAG,"Error:startScanner 存储不可用！");
        }
    }

    /**
     *停止扫描
     */
    public void stopScanner(){
        if(threadPool!=null){
            threadPool.shutdown();
        }
    }

    /**
     * 批量任务处理
     * @param files 批次任务根目录
     */
    private void doBatchTask(int key,final List<File> files){
        Log.i(TAG,"--doBatchTask,batchKey="+key+"，batchSize="+files.size());
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    List<File> tempFiles=files;
                    for(File obj:tempFiles) {
                        scannerDir(obj);
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * 计算每条线程该遍历的文件夹
     * @param root 根目录
     * @return
     */
    private SparseArray<List<File>> calculateScannerThreadBatch(String root){
        File rootDirFile = new File(root);
        //储存每一段线程需要跑的文件
        SparseArray<List<File>> sparseArray=new SparseArray();
        if(rootDirFile.exists()){
            File[] fileList=rootDirFile.listFiles();
            List<File> dataSource= (List) Arrays.asList(fileList);
            int batch=fileList.length/scannerThreadSize;
            if(batch==fileList.length){
                //一条线程跑完
                List list= Arrays.asList(fileList);
                sparseArray.append(1,list);
            }else{
                int step=1;
                int startIndex=0;
                int endIndex=0;
                for (int i=0;i<fileList.length;i++){
                    if(i%batch==0) {
                        startIndex=i;
                        endIndex=startIndex+batch;
                        if(fileList.length-i<batch) {
                            endIndex=fileList.length;
                        }
                        List<File> sub=dataSource.subList(startIndex, endIndex);
                        sparseArray.append(step,sub);
                        step++;
                    }
                }
            }
        }
        return sparseArray;
    }

    private void scannerDir(File dirFile) throws Exception {
        if (dirFile.exists()&&dirFile.isDirectory()) {
            File files[] = dirFile.listFiles();
            for (File file : files) {
                String fileName = file.getName();
                String filePath = file.getPath();
//                Log.i(TAG,"scanner filePath:"+filePath);
                if (file.isDirectory()) {
                    if (!fileName.endsWith("Android")) {
                        scannerDir(file);
                    }
                } else {
                    if(isImage(fileName)){
                        String imagePath="";
                        if (dirFile.getPath().endsWith(File.separator)) {
                            imagePath=dirFile.getPath() + file.getName();
                        } else {
                            imagePath=dirFile.getPath() + File.separator+ file.getName();
                        }
                        images.add(imagePath);
                        if(imageScannerResultListener!=null){
                            imageScannerResultListener.scannerSingeResult(startTime,file.getName(),imagePath);
                        }
                    }
                }
            }
        }else{
            String fileName = dirFile.getName();
            String filePath = dirFile.getPath();
            if(isImage(fileName)){
               images.add(filePath);
                if(imageScannerResultListener!=null){
                    imageScannerResultListener.scannerSingeResult(startTime,fileName,filePath);
                }
            }
        }
    }

    private boolean isImage(String fileName){
        if (fileName.endsWith(".jpg")
                || fileName.endsWith(".jpeg")
                || fileName.endsWith(".bmp")
                || fileName.endsWith(".gif")
                || fileName.endsWith(".png")) {
            return true;
        }
        return false;
    }
    public int getScannerThreadSize() {
        return scannerThreadSize;
    }

    public OkImageScanner setScannerThreadSize(int scannerThreadSize) {
        this.scannerThreadSize = scannerThreadSize;
        return okImageScanner;
    }

    public ImageScannerResultListener getImageScannerResultListener() {
        return imageScannerResultListener;
    }

    public OkImageScanner setImageScannerResultListener(ImageScannerResultListener imageScannerResultListener) {
        this.imageScannerResultListener = imageScannerResultListener;
        return okImageScanner;
    }
}
